import { Component, OnInit } from '@angular/core'
import { FormGroup, Validators, FormBuilder } from '@angular/forms'
import { ActivatedRoute } from '@angular/router'
import { NzMessageService } from 'ng-zorro-antd'

import { NewPageBaseClass } from '@shared/classes/NewPageBaseClass'
import { UserRole, User, ICreateUserForm } from '@shared/interfaces/user'
import { AcquirerService } from 'app/routes/acquirer/acquirer.service'
import { AcquirerAlinterService } from 'app/routes/acquirer/acquirer-alinter.service'
import { UserStoreService } from '../../user-store.service'
import { ERoleType, EUserType } from '@shared/enums'
import { encryptPassword, MustMatch } from 'app/utils/helpers'
import { UserService } from '../../user.service'
import {
  usernameReg,
  nicknameLength,
  emailReg,
  passwordMaxLength,
  passwordMinLength,
  usernameMaxLength,
  usernameMinLength,
  emailMaxLength,
} from 'app/utils/contraints'
import { UsernameConflictAsyncValidator, ValidateUserPassword } from 'app/utils/form-control.validator'
import { BusinessService } from '@shared/services/business.service'
import { I18NService } from '@core'
import { CommonAcquirerService } from '@shared/services/acquirer.service'
import { Observable, of } from 'rxjs'
import { AuditConfig, ExchangeRate, EAuditConfigType } from '@shared/interfaces/acquirer'
import { switchMap, map } from 'rxjs/operators'
import { EAuditType } from '@shared/interfaces/audit'

@Component({
  selector: 'app-user-new-user',
  templateUrl: './user.component.html',
  styleUrls: ['../../../../shared/styles/new-page-item.less'],
  providers: [{ provide: AcquirerService, useClass: AcquirerAlinterService }],
})
export class UserNewUserComponent extends NewPageBaseClass implements OnInit {
  validateForm: FormGroup
  userRoles: UserRole[]
  selectType: ERoleType
  errorTips = {}
  ERoleType = ERoleType
  EAuditType = EAuditType
  insCode: string

  exchangeRateStepID: number[] = []
  riskControlStepID: number[] = []
  operationStepID: number[] = []
  storeStepID: number[] = []
  transRefundStepID: number[] = []

  auditConfigs$: Observable<AuditConfig[]>

  auditConfigKVMap = {
    operation: this.operationStepID,
    store: this.storeStepID,
    riskControl: this.riskControlStepID,
    transRefund: this.transRefundStepID,
    exchangeRate: this.exchangeRateStepID,
  }

  constructor(
    public msg: NzMessageService,
    private fb: FormBuilder,
    private userService: UserService,
    private userStore: UserStoreService,
    private route: ActivatedRoute,
    private bizService: BusinessService,
    public i18n: I18NService,
    private commonAcquirerService: CommonAcquirerService,
  ) {
    super(msg, i18n)
  }

  ngOnInit(): void {
    const { insCode, type } = this.route.snapshot.queryParams
    this.insCode = insCode
    this.selectType = parseInt(type, 10)
    this.initAuditConfigs()
    this.initialUserForm()
    // either one is empty exit the function
    if (!insCode || type === ERoleType.Acquirer) {
      return
    }
    /**
     * How about intMerCode, intStoreCode and etc.
     */
    this.userService.getAcquirerRole(insCode, type).subscribe(roles => {
      this.userRoles = roles
    })
  }

  /** 机构用户审核权限配置 */
  initAuditConfigs(): void {
    this.auditConfigs$ = of(this.commonAcquirerService.viewingAcquirer.institution.common).pipe(
      switchMap(common => {
        if (common.insCode) {
          return of(common.auditConfigs.filter(config => !!config.type))
        } else {
          return this.commonAcquirerService
            .getFullAcquirerByInsCode(this.insCode)
            .pipe(
              map(
                acquirer =>
                  acquirer.institution.common.auditConfigs &&
                  acquirer.institution.common.auditConfigs.filter(config => !!config.type),
              ),
            )
        }
      }),
    )
  }

  initialUserForm() {
    const fb = {
      username: [
        ,
        [
          Validators.required,
          Validators.pattern(usernameReg),
          Validators.maxLength(usernameMaxLength),
          Validators.minLength(usernameMinLength),
        ],
      ],
      nickName: [, [Validators.required, Validators.maxLength(nicknameLength)]],
      email: [, [Validators.required, Validators.pattern(emailReg), Validators.maxLength(emailMaxLength)]],
      password: [
        ,
        [
          Validators.required,
          Validators.maxLength(passwordMaxLength),
          Validators.minLength(passwordMinLength),
          ValidateUserPassword,
        ],
      ],
      passwordCF: [, [Validators.required]],
      userRole: [, [Validators.required]],
    }

    this.validateForm = this.fb.group(fb, {
      validator: MustMatch('password', 'passwordCF'),
    })

    this.validateForm
      .get('username')
      .setAsyncValidators([UsernameConflictAsyncValidator(this.bizService, [this.validateForm], 'username')])
    this.initErrorTips()
  }

  pushDataToStore(): void {
    const type = parseInt(this.route.snapshot.queryParams['type'], 10)
    const businessCode = this.route.snapshot.queryParams['businessCode']

    const { userRole, passwordCF, password, ...rest } = this.validateForm.value
    const user: ICreateUserForm = { ...rest }
    // Assign userType in create
    switch (type) {
      case ERoleType.Acquirer: {
        user['userType'] = EUserType.Institution
        user['insCode'] = businessCode
        break
      }
      case ERoleType.Group: {
        user['userType'] = EUserType.Agent
        user['agentCode'] = businessCode
        break
      }
      case ERoleType.Merchant: {
        user['userType'] = EUserType.Merchant
        user['intMerCode'] = businessCode
        break
      }
      case ERoleType.Store: {
        user['userType'] = EUserType.Store
        user['intStoreCode'] = businessCode
        break
      }
    }

    if (userRole) {
      user['roleIDs'] = [userRole]
    }
    user['password'] = encryptPassword(password)
    user['auditPermissions'] = [
      ...this.operationStepID,
      ...this.riskControlStepID,
      ...this.storeStepID,
      ...this.exchangeRateStepID,
      ...this.transRefundStepID,
    ].filter(id => !!id || id === 0)

    this.userStore.updateValue(user as User)
  }

  selectChange(stepID: number[], type: EAuditConfigType): void {
    switch (type) {
      case EAuditConfigType.Operation:
        this.operationStepID = stepID
        break
      case EAuditConfigType.ExchangeRate:
        this.exchangeRateStepID = stepID
        break
      case EAuditConfigType.RiskControl:
        this.riskControlStepID = stepID
        break
      case EAuditConfigType.Store:
        this.storeStepID = stepID
        break
      case EAuditConfigType.TransRefund:
        this.transRefundStepID = stepID
        break
    }
  }

  checkValid() {
    if (!this.isValid()) {
      this.checkValidFail()
      return false
    }

    this.checkValidSuccess()
    return true
  }

  initErrorTips() {
    this.errorTips = {
      username: {
        required: this.trans('VALIDATION.REQUIRED', { name: this.trans('USER.USERNAME') }),
        maxLength: this.trans('VALIDATION.MAX_LENGTH', { length: usernameMaxLength }),
        minLength: this.trans('VALIDATION.MIN_LENGTH', { length: usernameMinLength }),
        pattern: this.trans('VALIDATION.PATTERN.USERNAME'),
        usernameConflicting: this.trans('VALIDATION.CODE_EXISTS', { name: this.trans('USER.USERNAME') }),
      },
      nickName: {
        required: this.trans('VALIDATION.REQUIRED', { name: this.trans('USER.NAME') }),
        maxLength: this.trans('VALIDATION.MAX_LENGTH', { length: nicknameLength }),
      },
      email: {
        required: this.trans('VALIDATION.REQUIRED', { name: this.trans('GENERAL.INFO.EMAIL') }),
        maxLength: this.trans('VALIDATION.MAX_LENGTH', { length: emailMaxLength }),
        pattern: this.trans('VALIDATION.PATTERN.EMAIL'),
      },
      password: {
        required: this.trans('VALIDATION.REQUIRED', { name: this.trans('USER.PASSWORD') }),
        maxLength: this.trans('VALIDATION.MAX_LENGTH', { length: passwordMaxLength }),
        minLength: this.trans('VALIDATION.MIN_LENGTH', { length: passwordMinLength }),
        passwordInvalid: this.trans('VALIDATION.PATTERN.PASSWORD'),
      },
      passwordCF: {
        mustMatch: '二次密码输入不一致',
      },
      userRole: {
        required: this.trans('VALIDATION.REQUIRED_SELECT', { name: this.trans('USER.USER_ROLE') }),
      },
    }
  }

  private isValid() {
    return this.validateForm.valid
  }

  private checkValidFail() {
    this.msg.error(this.trans('GENERAL.NOTIFICATION.VALIDATION_FAIL'))
    this.makeAllControlDirty(this.validateForm)
  }

  private checkValidSuccess() {
    this.msg.success(this.trans('GENERAL.NOTIFICATION.VALIDATION_SUCCESS'))
    this.pushDataToStore()
  }
}
